本章目標:透過兩個典型 IoT 任務,讓你理解「無 Wi-Fi 點對點通訊」與「前端控制實體裝置」的核心模式。
主題 A:ESP-NOW 無線短訊 × 加密解密 主題 B:ESP32 作為 Web Server 控制 RGB LED(Color Picker)
ESP32 除了可以用 Wi-Fi 上網,其實仲有另一套 不靠路由器(AP)都可通訊 的 protocol:
ESP-NOW = 超低延遲 × 不用 Wi-Fi × 點對點或廣播 × 只靠 MAC 地址通訊
你可以把佢理解為:
「ESP32 專用短訊網絡」
「本地機器之間互傳 message」
「不經網絡、不上互聯網」
「超快,極穩定」
常見用途:
IoT 節點之間交換資料(不需 AP)
Robot vs Robot 通訊
感測器 → 控制器
遊戲、遙控車、分散系統
Mesh Network(高階)
兩塊 ESP32 就可以做到本地通訊。
先用「明碼」發送 message。 下一部才加密。
在這個練習中,老師會用ESP32 NOW發送一段文字給你,你需要用ESP32接收老師給你訊息,然後在老師核對時,告訴老師你收到甚麼。
功能:每 5 秒廣播一段字串 message。你不需要上傳這段,這段老師已經做了,你負責接收訊息
33123
4uint8_t broadcastAddress[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // Broadcast5
6typedef struct struct_message {7 char msg[50];8} struct_message;9
10struct_message packet;11
12void setup() {13 Serial.begin(115200);14 WiFi.mode(WIFI_STA);15
16 if (esp_now_init() != ESP_OK) {17 Serial.println("ESP-NOW Init Failed");18 return;19 }20
21 esp_now_peer_info_t peerInfo = {};22 memcpy(peerInfo.peer_addr, broadcastAddress, 6);23 peerInfo.channel = 0;24 peerInfo.encrypt = false;25 esp_now_add_peer(&peerInfo);26}27
28void loop() {29 strcpy(packet.msg, "HELLO STUDENTS");30 esp_now_send(broadcastAddress, (uint8_t *)&packet, sizeof(packet));31 Serial.println("Sent: HELLO STUDENTS");32 delay(5000);33}功能:顯示收到的 message
30123
4typedef struct struct_message {5 char msg[50];6} struct_message;7
8struct_message incoming;9
10//收到訊息時會執行這一段====================================================11void onReceive(const esp_now_recv_info *info, const uint8_t *data, int len) {12 memcpy(&incoming, data, sizeof(incoming));13 Serial.print("收到訊息:");14 Serial.println(incoming.msg);15}16//收到訊息時會執行這一段====================================================17
18void setup() {19 Serial.begin(115200);20 WiFi.mode(WIFI_STA);21
22 if (esp_now_init() != ESP_OK) {23 Serial.println("ESP-NOW Init Failed");24 return;25 }26 //只要在setup()中注冊一次就可以, ESP32會在收到訊息時暫時中斷loop(),先執行onReceive()27 esp_now_register_recv_cb(onReceive);28}29
30void loop() {} //如果有其他別的內容,正常放在這裡就可以本章目標:在上一章的基礎上,讓 ESP32 之間的通訊提升至真正的「安全 IoT」級別。 ESP-NOW 原生支援 AES-128 加密,你只需要在「Peer 配對」階段加入 16 bytes Key, Sender 傳送時會自動加密,Receiver 收到後自動解密,程式不需要自己寫 encryption / decryption。
ESP32 的 ESP-NOW 通訊可以分為:
| 模式 | 是否安全 | 是否需要 Key | 適合用途 |
|---|---|---|---|
| 無加密(Open) | ❌ 不安全(可被嗅探) | ❌ 不需要 | 教學示範、簡單測試 |
| 加密(AES-128) | ✔ 安全 | ✔ 需要 16 字節 Key | 正式 IoT 通訊、同學互傳訊息、設備連線 |
ESP-NOW 使用的加密方式:
AES-128(ECB)硬件加速
Sender → AES Encrypt → RF 傳輸 → Receiver Firmware 自動解密 →
onReceive()取得明文
👉 完全感覺唔到加密存在,但安全性明顯更高。
ESP-NOW 加密需要固定 16 bytes(128 bits)key。
你可以:
用固定 key:uint8_t key[16] = { 0x01,0x02,... }
或者用15字節 ASCII(e.g. "1234567890ABCDEF")C 語言字串會自動加多一個 \0(Null terminator),所以如果用16個字節,實際會變成 17 bytes → 超出 ESP-NOW AES Key 的 16 bytes 限制。
示例 key:(15字節的String)
11"LOKCM is GENIUS"或 (16字節的Char array)
31uint8_t myKey[16] = {2 'L','O','K','C','M',' ','i','s',' ','G','E','N','I','U','S','!'3};AES 加密模式不支援 broadcast / multicast MAC 地址。 即:
FF:FF:FF:FF:FF:FF→ ❌ 不能加密 任何 group address(最低 bit = 1)→ ❌ 不能加密
➡ ESP-NOW 加密 只能用「單對單」MAC 對 MAC ➡ 不能「一部加密後廣播俾全班」
每隊 2 個學生、2 部 ESP32:
各自讀取本機 MAC
Sender 把 Receiver 的 MAC 填入程式
Receiver 把 Sender 的 MAC 填入程式
雙方使用 同一條 AES128 Key(16 bytes)
一端 send() → 另一端 onReceive() 自動解密
請每位學生先燒錄以下程式:
15123
4void setup() {5 Serial.begin(115200);6 WiFi.mode(WIFI_STA);7
8 uint8_t mac[6];9 esp_wifi_get_mac(WIFI_IF_STA, mac); // 永遠能讀到正確 MAC10
11 Serial.printf("ESP32 MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",12 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);13}14
15void loop(){}學生記錄輸出的 MAC,例如:
同學 A:7C:DF:A1:12:34:56
同學 B:B4:E6:2D:98:76:54
(把 Sender 的 MAC 貼進 senderMAC[])
接收端只需要接,唔需要 send 穩定度:極高 安全:已自動解密
49123
4typedef struct struct_message {5 char msg[50];6} struct_message;7
8struct_message incoming;9
10// 同學 A(Receiver) → 填入同學 B(Sender)的 MAC11uint8_t senderMAC[6] = 填入同學 B(Sender)的 MAC 例如咁 {0xB4,0xE6,0x2D,0x98,0x76,0x54};12
13// AES Key(16 bytes)14uint8_t myKey[16] = 改一個15字節密碼例如咁"LOKCM is Genius";15// 或者咁:16//uint8_t myKey[16] = {'L','O','K','C','M',' ','i','s',' ','G','E','N','I','U','S','!'};17
18void onReceive(const esp_now_recv_info *info, const uint8_t *data, int len) {19 memcpy(&incoming, data, sizeof(incoming));20
21 Serial.print("收到訊息:");22 Serial.println(incoming.msg);23}24
25void setup() {26 Serial.begin(115200);27 WiFi.mode(WIFI_STA);28
29 if (esp_now_init() != ESP_OK) {30 Serial.println("ESP-NOW Init Failed");31 return;32 }33
34 // 配對 Sender(必須)35 esp_now_peer_info_t peerInfo = {};36 memcpy(peerInfo.peer_addr, senderMAC, 6);37 peerInfo.channel = 0;38 peerInfo.encrypt = true; 39 memcpy(peerInfo.lmk, myKey, 16);40
41 if (esp_now_add_peer(&peerInfo) != ESP_OK) {42 Serial.println("Add Peer Failed");43 return;44 }45
46 esp_now_register_recv_cb(onReceive);47}48
49void loop(){}(把 Receiver 的 MAC 貼入 receiverMAC[])
加密後 send() 的資料會自動加密 → Receiver 自動解密 唔需要你寫 encryption/decryption。
47123
4typedef struct struct_message {5 char msg[50];6} struct_message;7
8struct_message packet;9
10// 同學 B(Sender) → 填入同學 A(Receiver)的 MAC11uint8_t receiverMAC[6] = 填入同學 A(Receiver)的 MAC例如咁{0x7C,0xDF,0xA1,0x12,0x34,0x56};12
13// AES Key(16 bytes)14uint8_t myKey[16] = 改一個15字節密碼例如咁"LOKCM is Genius";15// 或者咁:16//uint8_t myKey[16] = {'L','O','K','C','M',' ','i','s',' ','G','E','N','I','U','S','!'};17
18void setup() {19 Serial.begin(115200);20 WiFi.mode(WIFI_STA);21
22 if (esp_now_init() != ESP_OK) {23 Serial.println("ESP-NOW Init Failed");24 return;25 }26
27 // 配對 Receiver(必須)28 esp_now_peer_info_t peerInfo = {};29 memcpy(peerInfo.peer_addr, receiverMAC, 6);30 peerInfo.channel = 0;31 peerInfo.encrypt = true; 32 memcpy(peerInfo.lmk, myKey, 16);33
34 if (esp_now_add_peer(&peerInfo) != ESP_OK) {35 Serial.println("Add Peer Failed");36 return;37 }38}39
40void loop() {41 strcpy(packet.msg, "Hello from Sender!");42
43 esp_now_send(receiverMAC, (uint8_t*)&packet, sizeof(packet));44 Serial.println("已發送加密訊息。");45
46 delay(2000); // 每 2 秒發送一次47}| 步驟 | Receiver | Sender |
|---|---|---|
| 啟動 WiFi STA mode | ✔ | ✔ |
| 填入對方 MAC | ✔ senderMAC[] | ✔ receiverMAC[] |
| 設定相同 AES Key | ✔ | ✔ |
| add_peer() | ✔ | ✔ |
| 使用 encrypt=true | ✔ | ✔ |
| 使用 peerInfo.lmk | ✔ | ✔ |
只要其中一個設定錯誤 → 完全收不到訊息。
都是你之後常會遇到的問題

核心概念: ESP32 = Server(提供網頁) Browser = Client(按色板 → POST JSON → ESP32 控制 LED)
上一章,我們學習了前端、後端的概念。我們將前端放在 自己的電腦 上,用 VS Code 的 Live Server 去 host。這種方式只是本地測試,網頁只存在於電腦本身,其他裝置無法使用。
但如果介面不太複雜,我們可以 直接把網站架在 ESP32 裡面,將ESP32作為AP(Access Point)。
這樣做有不少明顯好處:
完全獨立運作,不依賴學校 Wi-Fi 或家用路由器: ESP32 自己開熱點, 學生手機直接連入即可。 避免校網密碼限制、網路隔離、AP Client 數量限制等問題。
部署成本極低、裝置即插即用: 只需要一條 USB 線即可運行整套系統; 不需要額外伺服器、路由器或雲端。
無網絡延遲與干擾,控制反應極快: AP 模式只有 ESP32 與你的裝置兩者通訊, 避免校園 Wi-Fi 擁塞導致的 delay、packet loss。
方便課堂示範與分組實驗: 每一組學生的 ESP32 都可以獨立開 AP, 各自的網頁和硬件互不干擾。
網站與硬件封裝在同一裝置內,學習概念更清晰:
ESP32 = Server(提供 HTML + JS)
Browser = Client(透過 HTTP 控制硬件)
完整理解前端→後端→硬件的資料流。
非常適合控制界面(Control Panel/UI): 色板、按鈕、Slider、LED 控制、馬達開關等操作, 都適合直接放在 ESP32 內,實作成本低、反應快。
在AP 模式:
ESP32 自己開 Wi-Fi 熱點
手機 / Notebook 直接連 ESP32
不需任何外部 Wi-Fi
不需 WiFi.begin()
不需 Router
75123
4WebServer server(80);5
6// 你想叫咩名都得7const char* ap_ssid = 麻煩你改改佢,唔係會同一時間有3x個同名wifi"ESP32-RGB";8const char* ap_pass = "12345678"; // 必須 ≥ 8 字符;如不想要密碼要特別寫法9
10int r_pin = 14, g_pin = 12, b_pin = 13;11
12String webpage = R"=====(13<!DOCTYPE html>14<html>15<body>16<h2>RGB LED 控制(AP 模式)</h2>17<input type="color" id="picker">18<script>19document.getElementById("picker").addEventListener("input", e => {20 fetch("/set", {21 method: "POST",22 headers: {"Content-Type":"application/json"},23 body: JSON.stringify({color: e.target.value})24 });25});26</script>27</body>28</html>29)=====";30
31void handleRoot(){32 server.send(200, "text/html", webpage);33}34
35void handleSet(){36 String body = server.arg("plain"); 37 int idx = body.indexOf("#");38 String hex = body.substring(idx+1, idx+7);39
40 long rgb = strtol(hex.c_str(), NULL, 16);41 int r = (rgb >> 16) & 255;42 int g = (rgb >> 8) & 255;43 int b = rgb & 255;44
45 analogWrite(r_pin, r);46 analogWrite(g_pin, g);47 analogWrite(b_pin, b);48
49 server.send(200, "text/plain", "OK");50}51
52void setup(){53 Serial.begin(115200);54 55 // ★★★ 關鍵:開 AP,不需要 WiFi.begin() ★★★56 WiFi.mode(WIFI_AP);57 WiFi.softAP(ap_ssid, ap_pass);58
59 Serial.print("AP 開啓,SSID:");60 Serial.println(ap_ssid);61 Serial.print("IP 地址:");62 Serial.println(WiFi.softAPIP()); // 通常是 192.168.4.163
64 pinMode(r_pin, OUTPUT);65 pinMode(g_pin, OUTPUT);66 pinMode(b_pin, OUTPUT);67
68 server.on("/", handleRoot);69 server.on("/set", HTTP_POST, handleSet);70 server.begin();71}72
73void loop(){74 server.handleClient();75}ESP32 通電後 → 自己開 Wi-Fi 熱點
SSID:ESP32-RGB
Password:12345678
學生手機 / Notebook 連接這個熱點
在瀏覽器輸入:
11http://192.168.4.1/
即可彈出你的 Color Picker 頁面。

本章透過兩個核心實作,讓你掌握 IoT 系統中最常見的兩種模式:
1|ESP-NOW 加密通訊(點對點)
使用 MAC 對 MAC 的方式建立連線
必須雙向配對 + 使用相同的 16-byte AES Key
傳輸過程由 ESP32 自動加密/解密
適合簡易控制訊息、分組互傳、近距離低延遲應用
2|ESP32 作為 AP + Web Server(控制 RGB LED)
ESP32 自行建立 Wi-Fi 熱點,手機直接連入
不依賴外部路由器,課堂操作最穩定
以瀏覽器載入 ESP32 提供的網頁,用 fetch() POST JSON 控制硬件
完整示範「前端 → 後端 → 硬件」資料流
你已掌握:
點對點安全通訊(ESP-NOW AES)
建立基本 Web API(/set)
HTML Color Picker × PWM 控 RGB
本章建立了 IoT 教學中兩個最重要的模型: 裝置間通訊 與 用瀏覽器控制硬件,為後續更多互動式 IoT 專題打好基礎。